﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ReplaceFileVersion
{
    public class ReplaceFileVersion
    {
        protected readonly List<string> Files = new List<string>();
#if DEBUG1
        protected readonly List<string> ScriptTags = new List<string>();
#endif
        protected Regex ScriptRegex = new Regex(@"<script[^src]*src=['""](.+?)['""][^>]*>\s*<\\?/script>", RegexOptions.IgnoreCase);
        protected Regex LinkRegex = new Regex(@"<link[^href]*href=['""](.+?)['""][^>]*>", RegexOptions.IgnoreCase);
        public string ReplacePattern { get; set; }
        public string ReplaceMent { get; set; }
        protected string LogDir { get; private set; }

        private ReplaceFileVersion()
        {
            ReplacePattern = @"\?v=(.*)['""&$]*";
            ReplaceMent = DateTime.Now.ToString("yyyyMMddHHmmss");
            var logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log");
            if (!Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }
            LogDir = logDir;
        }
        public ReplaceFileVersion(string filePath, string searchFilePattern)
            : this()
        {
            if (File.Exists(filePath))
            {
                Files.Add(filePath);
            }
            else if (Directory.Exists(filePath))
            {
                if (string.IsNullOrWhiteSpace(searchFilePattern))
                {
                    var fileArr = Directory.GetFiles(filePath, "*.*", SearchOption.AllDirectories);
                    Files.AddRange(fileArr);
                }
                else
                {
                    foreach (var s in searchFilePattern.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        var fileArr = Directory.GetFiles(filePath, s, SearchOption.AllDirectories);
                        Files.AddRange(fileArr);
                    }
                    Files = Files.Distinct().ToList();
                }
            }
            else
            {
                MessageBox.Show(string.Format("文件、目录[{0}]不存在！", filePath));
            }
        }

        public IDictionary<string, IList<string>> Replace()
        {
            var dict = new ConcurrentDictionary<string, IList<string>>();
            // var list = new ConcurrentQueue<string>();
            var regex = new Regex(ReplacePattern, RegexOptions.IgnoreCase);
            Parallel.ForEach(Files, path =>
            {
                var text = File.ReadAllText(path);
                var updateFile = false;
                var matches = ScriptRegex.Matches(text);
                var list = new List<string>();
                foreach (Match match in matches)
                {
                    if (match.Success)
                    {
                        var tag = match.Value;
#if DEBUG1
                        ScriptTags.Add(tag);
#endif
                        var attr = match.Groups[1].Value;
                        var mat = regex.Match(attr);
                        if (mat.Success)
                        {
                            var tmpV = mat.Groups[1].Value;
                            var newV = mat.Value.Replace(tmpV, ReplaceMent);
                            var newAttr = attr.Replace(mat.Value, newV);
                            list.Add(attr);
                            list.Add(newAttr);
                            var newTag = match.Value.Replace(attr, newAttr);
#if DEBUG1
                            ScriptTags.Add(newTag);
                            ScriptTags.Add(Environment.NewLine);
#endif
                            text = text.Replace(tag, newTag);
                            updateFile = true;
                        }
                    }
                }
                matches = LinkRegex.Matches(text);
                foreach (Match match in matches)
                {
                    if (match.Success)
                    {
                        var tag = match.Value;
#if DEBUG1
                        ScriptTags.Add(tag); 
#endif
                        var attr = match.Groups[1].Value;
                        var mat = regex.Match(attr);
                        if (mat.Success)
                        {
                            var tmpV = mat.Groups[1].Value;
                            var newV = mat.Value.Replace(tmpV, ReplaceMent);
                            var newAttr = attr.Replace(mat.Value, newV);
                            list.Add(attr);
                            list.Add(newAttr);
                            var newTag = match.Value.Replace(attr, newAttr);
#if DEBUG1
                            ScriptTags.Add(newTag);
                            ScriptTags.Add(Environment.NewLine);
#endif
                            text = text.Replace(tag, newTag);
                            updateFile = true;
                        }
                    }
                }
                if (updateFile)
                {
                    dict.TryAdd(path, list);
#if DEBUG1
                    File.WriteAllText(path + ".bak", text);
#else
                    File.WriteAllText(path, text);
#endif
                }
            });
#if DEBUG1
            File.WriteAllLines("d:\\replaceFileVersion.log", ScriptTags); 
#endif
            return dict;
        }

        public string WriteLog(IDictionary<string, IList<string>> list)
        {
            var path = Path.Combine(LogDir, "UpdateFile_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".log");
            var sb = new StringBuilder();
            foreach (var item in list)
            {
                sb.AppendLine(item.Key);
                foreach (var line in item.Value)
                {
                    sb.Append("     ").AppendLine(line);
                }
                sb.AppendLine().AppendLine();
            }
            File.WriteAllText(path, sb.ToString());
            return path;
        }

        public static void AppendDirHistory(string dir)
        {
            var conf = GetHistoryFilePath();
            var his = GetDirHistory();
            his.Remove(dir);
            his.Insert(0, dir);
            File.WriteAllLines(conf, his);
        }

        private static string GetHistoryFilePath()
        {
            var conf = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "ReplaceFileVersionFormSelectedPath.data";
           
            return conf;
        }

        public static List<string> GetDirHistory()
        {
            var list = new List<string>();
            var conf = GetHistoryFilePath();
            if (!File.Exists(conf))
            {
                return list;
            }
            list.AddRange(File.ReadAllLines(conf));
            return list;
        }

    }
}
